/**
 * Sensor Network Development Kit for 1-Wire Network (SeN)
 * Version : 0.1
 * Revision date : 2008-10-13
 * Author: Dubravko Penezic, dpenezic@gmail.com
 * 
 * Based on T. Bitson, SimpleWeather, HumiditySensor.java, 2007
 */

package owSensor;


import com.dalsemi.onewire.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;

import owLib.*;

/**
 * HumiditySensor class implement method to read DS2438 and humidity sensor
 * Version : 0.1.1
 * Revision date : 2008-10-18
 * 
 * @author Dubravko Penezic, dpenezic@gmail.com
 *
 */

public class HumiditySensor
{
  // calibration constants
  private float HUMIDITY_OFFSET = 0.0f;
  private float HUMIDITY_GAIN   = 1.0f;
  
  // class variables

  private DSPortAdapter adapter;
  private OWDevice device;
  private OneWireContainer26 humidityDevice = null;
  private static boolean debugFlag = OWConf.debugFlag;
  private OWCommPath p;
  
  private String sensorType="HIH-4000";
  private double temp = -999.99d;
  
/** 
 * HumiditySensor method configure class parameters and create soft link to 1-Wire device
 *  
 * @param adapter
 * @param device
 * @param sensorType
 */
  public HumiditySensor(DSPortAdapter adapter, OWDevice device, String sensorType)
  {
	    this.adapter = adapter;
	    this.device = device;
	    this.p = new OWCommPath(this.adapter, this.device);
    
	    setSensorType(sensorType);
        humidityDevice = new OneWireContainer26(adapter, device.getDAddress());
  }
   
/**
 * getHumidity method read DS2438 and depend of humidity sensor type return relative humidity like percentage
 * 
 * @return
 */
  public float getHumidity()
  {
    float humidity = -999.9f;
    
    if (humidityDevice != null)
    {
      if (debugFlag)
      {
        System.out.print("Humidity: Device = " + humidityDevice.getName());
        System.out.print("  ID = " + humidityDevice.getAddressAsString() + "\n");
      }
      
      // activate path to device
      p.activatePath();
      
      try
      {
        // read 1-wire device's 
        byte[] state = humidityDevice.readDevice();
        
        if(sensorType.equalsIgnoreCase("HIH-3610") && temp<-999){
            humidityDevice.doTemperatureConvert(state);
            temp = humidityDevice.getTemperature(state);               	
        }
        
        // Read humidity sensor's output voltage
        humidityDevice.doADConvert(OneWireContainer26.CHANNEL_VAD, state);
        double Vad = humidityDevice.getADVoltage(OneWireContainer26.CHANNEL_VAD, state);
        
        // Read the humidity sensor's power supply voltage
        humidityDevice.doADConvert(OneWireContainer26.CHANNEL_VDD, state);
        double Vdd = humidityDevice.getADVoltage(OneWireContainer26.CHANNEL_VDD, state);
        
        // calculate humidity
        if(sensorType.equalsIgnoreCase("HIH-4000")) humidity = hih4000calc(Vdd,Vad);
        if(sensorType.equalsIgnoreCase("HIH-3610")) humidity = hih3610calc(Vdd,Vad,temp);
        
        if (debugFlag)
        {
          System.out.println("Supply Voltage = " + Vdd + " Volts");
          System.out.println("Sensor Output  = " + Vad + " Volts");
          System.out.println("Temperature    = " + temp + " C / ");
          System.out.println("Hum Gain       = " + HUMIDITY_GAIN);
          System.out.println("Hum Offset     = " + HUMIDITY_OFFSET);
          System.out.println("Calibrated RH   = " + humidity + "%\n");
        }
      }
      catch (OneWireException e)
      {
        System.out.println("Error Reading Humidity: " + e);
      }
    }
    
    // deactivate path to device
    p.deactivatePath();
    
    return humidity;
  }
   
/**
 * calcDewpoint method calculate the dewpoint from relative humidity & temperature
 * 
 * The dew point (sometimes spelled dewpoint) is the temperature to which a given parcel of air must be cooled, at constant barometric pressure, for water vapor to condense into water.
 * 
 * @param hum
 * @return
 */
  public float calcDewpoint(float hum)
  {
    // compute the dewpoint from relative humidity & temperature
     
    // now convert to degrees K
    double tempK = temp + 273.15;
    
    // calc dewpoint
    double dp = tempK/((-0.0001846 * Math.log(hum/100.0) * tempK) + 1.0);
    
    // convert back to degrees C
    dp = dp - 273.15;
       
    return (float)dp;
  }

/**
 * setHumidityGain method set gain for calibration results of humidity
 *   
 * @param hg
 */
  public void setHumidityGain(float hg){
	  
	  HUMIDITY_GAIN = hg;
	  
  }

/**
 * 
 * setHumidityOffset method set offset for calibration results of humidity
 * 
 * @param ho
 */
  public void setHumidityOffset(float ho){

	  HUMIDITY_OFFSET = ho;

  }
  
/**
 * setTemperature method to set temperature of internal variable for use in temperature correction and calculating dew point
 * 
 * @param temp
 */
  public void setTemperature(double temp){
	  
	  this.temp = temp;
	  
  }

/**
 * setSensorType internal method to set humidity sensor type variable
 * 
 * @param name
 */
  private void setSensorType(String name){
	  
	  if(name.equalsIgnoreCase("HIH-4000")) sensorType="HIH-4000";
	  if (name.equalsIgnoreCase("HIH-3610")) sensorType="HIH-3610";

  }
  
/**
 * 
 * hih4000calc method calculate relative humidity base on output voltage from HIH-4000 sensor series
 * 
 * @param Vdd supply voltage
 * @param Vad sensor output voltage
 * @return relative humidity in percentage
 */
  private float hih4000calc(double Vdd, double Vad){

	  // HIH 4000 series have internal temperature sensor and apply temperature correction automatically 
	  float humidity = (float) ((Vad/Vdd - 0.16) / 0.0062);

      // apply calibration
      humidity = humidity * HUMIDITY_GAIN + HUMIDITY_OFFSET;
	  
	  return humidity;
  }

  /**
 * 
 * hih3610calc method calculate relative humidity base on output voltage from HIH-3610 sensor series and implement temperature correction
 * 
 * @param Vdd supply voltage
 * @param Vad sensor output voltage
 * @param temp in C
 * @return relative humidity in percentage
 */
  private float hih3610calc(double Vdd, double Vad, double temp){

      double rh = (Vad/Vdd - 0.16) / 0.0062;
      
      // temperature correction
      float humidity = (float)(rh / (1.0546 - 0.00216 * temp));
      
      // apply calibration
      humidity = humidity * HUMIDITY_GAIN + HUMIDITY_OFFSET;
	  
	  return humidity;
  }

}
